import { ScriptAttributes } from './template.type';
import YbMicro from '../modules/sandbox';

declare global {
  interface Window {
    // 是否存在无界
    __POWERED_BY_YBMICRO__?: boolean;
    // 子应用公共加载路径
    __YBMICRO_PUBLIC_PATH__: string;
    // 原生的querySelector
    __YBMICRO_RAW_DOCUMENT_QUERY_SELECTOR__: typeof Document.prototype.querySelector;

    // iframe内原生的createElement
    __YBMICRO_RAW_DOCUMENT_CREATE_ELEMENT__: typeof Document.prototype.createElement;

    // iframe内原生的createTextNode
    __YBMICRO_RAW_DOCUMENT_CREATE_TEXT_NODE__: typeof Document.prototype.createTextNode;

    // iframe内原生的head
    __YBMICRO_RAW_DOCUMENT_HEAD__: typeof Document.prototype.head;

    // 原生的querySelector
    __YBMICRO_RAW_DOCUMENT_QUERY_SELECTOR_ALL__: typeof Document.prototype.querySelectorAll;
    // 原生的window对象
    __YBMICRO_RAW_WINDOW__: Window;
    // 子应用沙盒实例
    __YBMICRO: YbMicro;
    // 记录注册在主应用中的事件
    __YBMICRO_EVENTLISTENER__: Set<{
      listener: EventListenerOrEventListenerObject;
      type: string;
      options: any;
    }>;
    // 子应用mount函数
    __YBMICRO_MOUNT: () => void;
    // 子应用unmount函数
    __YBMICRO_UNMOUNT: () => void;
    // document type
    Document: typeof Document;
    // img type
    HTMLImageElement: typeof HTMLImageElement;
    // node type
    Node: typeof Node;
    // element type
    Element: typeof Element;
    // htmlElement typeof
    HTMLElement: typeof HTMLElement;
    // anchor type
    HTMLAnchorElement: typeof HTMLAnchorElement;
    // source type
    HTMLSourceElement: typeof HTMLSourceElement;
    // link type
    HTMLLinkElement: typeof HTMLLinkElement;
    // script type
    HTMLScriptElement: typeof HTMLScriptElement;
    // media type
    HTMLMediaElement: typeof HTMLMediaElement;
    EventTarget: typeof EventTarget;
    Event: typeof Event;
    // 注入对象
    $ybmicro: { [key: string]: any };
  }
  interface HTMLHeadElement {
    _cacheListeners: Map<string, EventListenerOrEventListenerObject[]>;
  }
  interface HTMLBodyElement {
    _cacheListeners: Map<string, EventListenerOrEventListenerObject[]>;
  }
  interface Document {
    createTreeWalker(
      root: Node,
      whatToShow?: number,
      filter?: NodeFilter | null,
      entityReferenceExpansion?: boolean
    ): TreeWalker;
  }
}

export interface ScriptObjectLoader {
  /** 脚本地址，内联为空 */
  src?: string;
  /** 脚本是否为module模块 */
  module?: boolean;
  /** 脚本是否为async执行 */
  async?: boolean;
  /** 脚本是否设置crossorigin */
  crossorigin?: boolean;
  /** 脚本crossorigin的类型 */
  crossoriginType?: 'anonymous' | 'use-credentials' | '';
  /** 脚本原始属性 */
  attrs?: ScriptAttributes;
  /** 内联script的代码 */
  content?: string;
  /** 执行回调钩子 */
  callback?: (appWindow: Window) => any;
  /** 子应用加载完毕事件 */
  onload?: Function;
}

export type loadErrorHandler = (url: string, e: Error) => any;

export type baseOptions = {
  /** 唯一性用户必须保证 */
  name: string;
  /** 需要渲染的url */
  url: string;
  /** 注入给子应用的属性 */
  props?: { [key: string]: any };
  /** 子应用生命周期 */
  beforeLoad?: lifecycle;
  beforeMount?: lifecycle;
  afterMount?: lifecycle;
  beforeUnmount?: lifecycle;
  afterUnmount?: lifecycle;
  activated?: lifecycle;
  deactivated?: lifecycle;
  loadError?: loadErrorHandler;
};

export type startOptions = baseOptions & {
  /** 渲染的容器 */
  el: HTMLElement | string;
  /**
   * 路由同步开关
   * 如果false，子应用跳转主应用路由无变化，但是主应用的history还是会增加
   */
  /** 子应用短路径替换，路由同步时生效 */
  prefix?: { [key: string]: string };
  /** 子应用加载时loading元素 */
  loading?: HTMLElement;
};

export type optionProperty = 'url' | 'el';

export type lifecycle = (appWindow: Window) => any;
export type lifecycles = {
  beforeLoad: lifecycle;
  beforeMount: lifecycle;
  afterMount: lifecycle;
  beforeUnmount: lifecycle;
  afterUnmount: lifecycle;
  activated: lifecycle;
  deactivated: lifecycle;
  loadError: loadErrorHandler;
};

/**
 * 合并 preOptions 和 startOptions，并且将 url 和 el 变成可选
 */
export type cacheOptions = Omit<startOptions, optionProperty> &
  Partial<Pick<startOptions, optionProperty>>;
